package com.lenovo.mso2o.service;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;

import com.lenovo.framework.FApplication;
import com.lenovo.framework.base.BaseService;
import com.lenovo.framework.biz.ContextManager;
import com.lenovo.framework.entity.Res;
import com.lenovo.framework.rest.CountingRequestBody;
import com.lenovo.framework.util.BitmapHelper;
import com.lenovo.framework.util.DLog;
import com.lenovo.framework.util.FPreferenceManager;
import com.lenovo.framework.util.FileHelper;
import com.lenovo.mso2o.MSApplication;
import com.lenovo.mso2o.biz.AccountManagerImpl;
import com.lenovo.mso2o.conf.MSConstants;
import com.lenovo.mso2o.entity.FAttachment;
import com.lenovo.mso2o.entity.g.Attachment;
import com.lenovo.mso2o.entity.g.AttachmentDao;
import com.lenovo.mso2o.rest.MediaAPI;
import com.lenovo.mso2o.rest.ServiceGenerator;
import com.lenovo.mso2o.util.CommonUtil;
import com.lenovo.framework.util.FileSizeHelper;
import com.lenovo.mso2o.util.Utils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import retrofit2.Response;

/**
 * Created by hejie5 on 2016/3/20.
 */
public class UploadService extends BaseService{

    public static final String ACTION_LOCAL_ATTACHMENT_INSERT = "com.lenovo.mso2o.LOCAL.ATTACHEMENT.INSERT";
    private static final String ACTION_START = "com.lenovo.mso2o.ACTION_START";
    private static final String KEY_ATTACHMENT_LIST = "attachment";
    public static final String REFRESH_TOTAL_UPLOADING_MB = "refresh_total_uploading_mb";
    private MediaAPI mPushClient = null;
    private static AttachmentDao dao = MSApplication.getDaoSession().getAttachmentDao();

    public static void actionStart(Context ctx)
    {
        Intent i = new Intent(ctx, UploadService.class);
        i.setAction(ACTION_START);
        ctx.startService(i);
    }

    public static void actionLocalAttachInsert(Context ctx, ArrayList<FAttachment> list) {
        DLog.i(UploadService.class.getName(), "attach insert");
        if (!AccountManagerImpl.instance.isLogin()) return;

        Bundle data = new Bundle();
        data.putParcelableArrayList(KEY_ATTACHMENT_LIST, list);
        Intent i = new Intent(ctx, UploadService.class);
        i.setAction(ACTION_LOCAL_ATTACHMENT_INSERT);
        i.putExtras(data);
        ctx.startService(i);
    }

    @Override
    public IBinder onBind(Intent intent) {
        DLog.i(getClass().getName(), "onBind");
        return super.onBind(intent);
    }


    @Override
    public void onCreate() {
        DLog.i(getClass().getName(), "onCreate");
        super.onCreate();
    }

    @Override
    public int onStartCommand(final Intent intent, int flags, int startId) {
        DLog.w("upload", "startcommand");
        super.onStartCommand(intent, flags, startId);
        if (intent == null || intent.getAction() == null || intent.getExtras() == null) {
            restartIfNecessary();
            return START_STICKY;
        }
        Bundle data = intent.getExtras();
        final ArrayList<FAttachment> args = data.getParcelableArrayList(KEY_ATTACHMENT_LIST);
        if (intent.getAction().equals(ACTION_LOCAL_ATTACHMENT_INSERT)) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (UploadService.class) {
                        Bundle data = intent.getExtras();
                        final ArrayList<FAttachment> args = data.getParcelableArrayList(KEY_ATTACHMENT_LIST);
                        String account = FPreferenceManager.getString(MSConstants.ACCOUNT_SIGNED, "");
                        for (FAttachment newAttachment : args) {
                            if (newAttachment.getLazyId() == null || newAttachment.getTicketid() == null)
                                return;
                            List<Attachment> same = dao.queryBuilder().where(
                                    AttachmentDao.Properties.LazyId.notEq(newAttachment.getLazyId()),
                                    AttachmentDao.Properties.Ticketid.notEq(newAttachment.getTicketid()),
                                    AttachmentDao.Properties.Account.eq(account)
                            ).list();
                            if (same == null || same.size() == 0) {
                                File newFile = new File(MSApplication.getDataDir(), "file");
                                FileHelper.ensureDir(newFile.getAbsolutePath());
                                String path = newAttachment.getPath();
                                String newPath = newFile.getPath() + "/" + FileHelper.getHashAbleFileName(path, null);
                                try {
                                    FileHelper.copyFile(newAttachment.getPath(), newPath);
                                    newAttachment.setPath(newPath);
                                    newAttachment.setAccount(account);
                                    dao.insert(newAttachment);
                                    FApplication.getRxBus().send(REFRESH_TOTAL_UPLOADING_MB);
                                    DLog.d("newPath:", newPath);
                                    //FileHelper.delete(path);
                                } catch (IOException e) {
                                    DLog.p(e);
                                }
                            }
                        }
                        restartIfNecessary();
                    }
                }
            }).start();
        }else {
            restartIfNecessary();
        }
        return START_STICKY;
    }

    /* get upload attaments include:
     * a. failed uploaded attachment(retry after 2^failedCount　time
     * b. new attachment
     */
    private static synchronized List<Attachment> getAttachTodos(){
        String account = FPreferenceManager.getString(MSConstants.ACCOUNT_SIGNED, "");
        List<Attachment> todos = dao.queryBuilder().where(AttachmentDao.Properties.Status.eq(1),
                AttachmentDao.Properties.Account.eq(account)
                ).list();
        if (todos != null && todos.size() > 0) {
            for (Attachment a : todos) {
                if (a.getFailedTime() > 0) {
                   // if (a.getFailedTime() > 3 || System.currentTimeMillis() - a.getTime() > MSConstants.UPLOAD_FAIL_DURATION * Math.pow(2, a.getFailedTime() - 1)) {
                    if (System.currentTimeMillis() - a.getTime() > MSConstants.UPLOAD_FAIL_DURATION * Math.pow(2, a.getFailedTime() - 1)) {
                        a.setStatus(0);
                        dao.update(a);
                    }
                }
            }
        }
        return dao.queryBuilder().where(AttachmentDao.Properties.Status.eq(0),
                AttachmentDao.Properties.Account.eq(account)
                ).list();
    }

    //根据连接模式判断连接状态可以上传图片, 附件
    public static boolean isConnectedNecessary(){
        //默认wifi上传
        if(FPreferenceManager.getBoolean(MSConstants.KEY_UPLOAD_MODE_WIFI_ONLY, false)){
            return CommonUtil.isWifiConnected(ContextManager.context());
        }else{
            return CommonUtil.isNetworkAvailable(ContextManager.context());
        }
    }
    public static boolean shouldRestart(){
        DLog.i("upload", "" + isConnectedNecessary());
        if (isConnectedNecessary()){
            List<Attachment> todos = getAttachTodos();
            if(todos != null
                && todos.size() > 0) {
                DLog.i("upload", "" + todos.size());
                return true;
            }
        }
        return false;
    }

    public static void actionStop(Context ctx)
    {
        BaseService.actionStop(ctx, UploadService.class);
    }

    synchronized protected void restartIfNecessary()
    {
        List<Attachment> todos = getAttachTodos();
        if (isConnectedNecessary()
                && todos != null
                && todos.size() > 0) {
            DLog.w(getClass().getName(), "Reconnecting...");
            if (todos.size() > 0) {
                connect();
            }
        }
    }

    public static double getUploadingMB(){
        String account = FPreferenceManager.getString(MSConstants.ACCOUNT_SIGNED, "");
        List<Attachment> uploads = dao.queryBuilder().where(
            AttachmentDao.Properties.Account.eq(account)).list();
        double total = 0.0;
        for(Attachment a : uploads){
            total += FileSizeHelper.getFileOrFilesSize(a.getPath(), FileSizeHelper.SIZETYPE_MB);
        }
        return total;
    }

    private void connect() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (UploadService.class) {
                    List<Attachment> todos = getAttachTodos();
                    while (todos != null && todos.size() != 0) {
                        DLog.w(getClass().getName(), todos.size() + "");
                        if (!AccountManagerImpl.instance.isLogin()) return;
                        todos = getAttachTodos();
                        if (todos == null
                                || todos.size() == 0
                                || !isConnectedNecessary()) {
                            DLog.p("" + todos.size());
                            stop();
                            return;
                        }
                        Attachment a = todos.get(0);
                        if (a.getFailedTime() > MSConstants.UPLOAD_FAIL_MAXTIME) {
                            dao.delete(a);
                            FApplication.getRxBus().send(REFRESH_TOTAL_UPLOADING_MB);
                            new File(a.getPath()).delete();
                            continue;
                        }
                        try {
                            String extension = FileHelper.splitExtension(a.getPath());
                            if ("png".equals(extension)
                                    || "jpg".equals(extension)
                                    || "jpeg".equals(extension)) {
                                double sizeKB = FileSizeHelper.getFileOrFilesSize(a.getPath(), FileSizeHelper.SIZETYPE_KB);
                                if (sizeKB > MSConstants.LIMITS.IMAGE_UPLOAD_MAX_KB)
                                    if (!a.getPath().contains("scaled")) {
                                        Bitmap scaledBitmap =
                                                BitmapHelper.safeDecodeScaledBitmapFromFileSystem(a.getPath(), MSConstants.LIMITS.IMAGE_UPLOAD_MAX_WIDTH,
                                                        MSConstants.LIMITS.IMAGE_UPLOAD_MAX_HEIGHT);
                                        Bitmap sizedBitmap = BitmapHelper.shrinkBitmap(scaledBitmap, MSConstants.LIMITS.IMAGE_UPLOAD_MAX_KB);
                                        String scaleDir = MSApplication.getDataDir() + "/scaled/";
                                        FileHelper.ensureDir(scaleDir);
                                        String newPath = scaleDir + FileHelper.getHashAbleFileName(a.getPath(), null);
                                        boolean success = BitmapHelper.toFile(
                                                sizedBitmap, new File(newPath));
                                        DLog.d("scale:", "" + success);
                                        DLog.d("scaledPath:", newPath);
                                        if (success) {
                                            new File(a.getPath()).delete();
                                            a.setPath(newPath);
                                            dao.update(a);
                                        } else {
                                            a.setFailedTime(a.getFailedTime() + 1);
                                            if (a.getFailedTime() > MSConstants.UPLOAD_FAIL_MAXTIME) {
                                                DLog.d("failed:", a.getPath());
                                                dao.delete(a);
                                                FApplication.getRxBus().send(REFRESH_TOTAL_UPLOADING_MB);
                                            } else {
                                                a.setStatus(1);
                                                dao.update(a);
                                                FApplication.getRxBus().send(REFRESH_TOTAL_UPLOADING_MB);
                                            }
                                            continue;
                                        }
                                    }
                            }
                            DLog.d("path:", a.getPath());
                            DLog.d("exist:", "" + FileHelper.exists(a.getPath()));
                            if (!FileHelper.exists(a.getPath())) {
                                dao.delete(a);
                                FApplication.getRxBus().send(REFRESH_TOTAL_UPLOADING_MB);
                                continue;
                            }
                            RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), new File(a.getPath()));
                            mPushClient = ServiceGenerator.createService(MediaAPI.class, new CountingRequestBody.Listener() {
                                @Override
                                public void onRequestProgress(long bytesWritten, long contentLength) {
                                    //TODO update ui;
                                }
                            });
                            Response<Res> res =
                                    mPushClient.uploadAttachmentAsync(
                                            fileBody, a.getLazyId(), a.getTicketid()
                                    ).execute();
                            if (res.body() != null && res.body().getEcode() == 0) {
                                DLog.toast("upload success");
                                DLog.d("success", a.getPath());
                                dao.delete(a);
                                new File(a.getPath()).delete();
                                FApplication.getRxBus().send(REFRESH_TOTAL_UPLOADING_MB);
                            } else {
                                DLog.d("fail:", res.body() + "");
                                if (AccountManagerImpl.instance.isLogin()) {
                                    a.setFailedTime(a.getFailedTime() + 1);
                                    a.setTime(System.currentTimeMillis());
                                    a.setStatus(1);
                                    dao.update(a);
                                } else {
                                    DLog.p("not login:" + todos.size());
                                    stop();
                                    return;
                                }
                            }
                        } catch (Exception e) {
                            DLog.d("upload:", "exception:" + e.getMessage());
                            if (AccountManagerImpl.instance.isLogin()) {
                                a.setFailedTime(a.getFailedTime() + 1);
                                a.setTime(System.currentTimeMillis());
                                a.setStatus(1);
                                dao.update(a);
                            } else {
                                DLog.p("not login:" + todos.size());
                                stop();
                                return;
                            }
                        }
                    }
                }
            }
        }).start();
    }

    @Override
    public void onDestroy() {
        DLog.w(this.getClass().getName(), "onDestroy");
        super.onDestroy();
    }

    protected void onStart() {


        connect();
    }

    protected void onStop() {

        cancelRestart(UploadService.class);
        if (mPushClient != null)
        {
            mPushClient = null;
        }
    }

    protected void onError() {
        if (!mStarted) {
        } else {

            mPushClient = null;

            if(isNetworkAvailable()) {
                scheduleRestart(UploadService.class);
            }
        }
    }

}
